/**
 * @file    gt98xx_drv_spi.c
 * @author  Giantec-Semi ATE
 * @brief   Source file of SPI driver module.
 * @version 0.1
 * 
 * @copyright Copyright (c) 2021 Giantec-Semi
 */

#include "gt98xx_drv_spi.h"

/**
 * @addtogroup GT98xx_DRV
 * @{
 */

/**
 * @addtogroup SPI_DRV
 * @{
 */

/**
 * @addtogroup SPI_DRV_Private_Macros
 * @{
 */

/**
 * @def IS_DRV_SPI_TRANSFER_DIRECTION
 * @brief Check if __VALUE__ is SPI transfer direction type
 */
#define IS_DRV_SPI_TRANSFER_DIRECTION(__VALUE__)    (((__VALUE__) == DRV_SPI_FULL_DUPLEX) || \
                                                     ((__VALUE__) == DRV_SPI_SIMPLEX_3WIRE) || \
                                                     ((__VALUE__) == DRV_SPI_SIMPLEX_TXONLY) || \
                                                     ((__VALUE__) == DRV_SPI_HALF_DUPLEX_RX) || \
                                                     ((__VALUE__) == DRV_SPI_HALF_DUPLEX_TX))

/**
 * @def IS_DRV_SPI_MODE
 * @brief Check if __VALUE__ is SPI mode type
 */
#define IS_DRV_SPI_MODE(__VALUE__)                  (((__VALUE__) == DRV_SPI_MODE_MASTER) || \
                                                     ((__VALUE__) == DRV_SPI_MODE_SLAVE))

/**
 * @def IS_DRV_SPI_DATAWIDTH
 * @brief Check if __VALUE__ is data width type
 */
#define IS_DRV_SPI_DATAWIDTH(__VALUE__)             (((__VALUE__) == DRV_SPI_DATAWIDTH_4BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_5BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_6BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_7BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_8BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_9BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_10BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_11BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_12BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_13BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_14BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_15BIT) || \
                                                     ((__VALUE__) == DRV_SPI_DATAWIDTH_16BIT))

/**
 * @def IS_DRV_SPI_POLARITY
 * @brief Check if __VALUE__ is polarity type
 */
#define IS_DRV_SPI_POLARITY(__VALUE__)              (((__VALUE__) == DRV_SPI_POLARITY_LOW) || \
                                                     ((__VALUE__) == DRV_SPI_POLARITY_HIGH))

/**
 * @def IS_DRV_SPI_CLOCKPHASE
 * @brief Check if __VALUE__ is clock phase type
 */
#define IS_DRV_SPI_CLOCKPHASE(__VALUE__)            (((__VALUE__) == DRV_SPI_PHASE_1EDGE) || \
                                                     ((__VALUE__) == DRV_SPI_PHASE_2EDGE))

/**
 * @def IS_DRV_SPI_BAUDRATEPRESCALER
 * @brief Check if __VALUE__ is baud rate prescaler type
 */
#define IS_DRV_SPI_BAUDRATEPRESCALER(__VALUE__)     (((__VALUE__) == DRV_SPI_BAUDRATEPRESCALER_DIV2) || \
                                                     ((__VALUE__) == DRV_SPI_BAUDRATEPRESCALER_DIV4) || \
                                                     ((__VALUE__) == DRV_SPI_BAUDRATEPRESCALER_DIV8) || \
                                                     ((__VALUE__) == DRV_SPI_BAUDRATEPRESCALER_DIV16) || \
                                                     ((__VALUE__) == DRV_SPI_BAUDRATEPRESCALER_DIV32) || \
                                                     ((__VALUE__) == DRV_SPI_BAUDRATEPRESCALER_DIV64) || \
                                                     ((__VALUE__) == DRV_SPI_BAUDRATEPRESCALER_DIV128) || \
                                                     ((__VALUE__) == DRV_SPI_BAUDRATEPRESCALER_DIV256))

/**
 * @def IS_DRV_SPI_SIGNIFICANTBIT
 * @brief Check if __VALUE__ is significant bit type
 */
#define IS_DRV_SPI_SIGNIFICANTBIT(__VALUE__)        (((__VALUE__) == DRV_SPI_MSB) || \
                                                     ((__VALUE__) == DRV_SPI_LSB))

/** @} SPI_DRV_Private_Macros */

/**
 * @addtogroup SPI_DRV_Exported_Functions
 * @{
 */

/**
 * @addtogroup SPI_DRV_EF_Init
 * @{
 */

/**
 * @fn ErrorStatus DrvSpiDeInit(SpiTypedef* spi_instance)
 * @brief De-initialize SPI registers
 * 
 * @param[in] spi_instance SPI instance
 * @return SPI is de-initialized or not
 * @retval kSuccess SPI registers are de-initialized
 * @retval kError SPI registers are not de-initialized
 */
ErrorStatus DrvSpiDeInit(SpiTypedef* spi_instance) {
  ErrorStatus status = kSuccess;

  assert_param(IS_SPI_ALL_INSTANCE(spi_instance));
  if (SPI1 == spi_instance) {
    CLEAR_BIT(RST_CTL_REG->MCU_BLK_RST, MCU_BLK_RST_SPI1);
    SET_BIT(RST_CTL_REG->MCU_BLK_RST, MCU_BLK_RST_SPI1);
  } else if (SPI2 == spi_instance) {
    CLEAR_BIT(RST_CTL_REG->MCU_BLK_RST, MCU_BLK_RST_SPI2);
    SET_BIT(RST_CTL_REG->MCU_BLK_RST, MCU_BLK_RST_SPI2);
  } else {
    status = kError;
  }
  return status;
}

/**
 * @fn ErrorStatus DrvSpiInit(SpiTypedef* spi_instance, DrvSpiInitTypedef* spi_init_struct)
 * @brief Initialize the SPI registers according to the specified parameters in DrvSpiInitTypedef
 * 
 * @param[in] spi_instance SPI instance
 * @param[in] spi_init_struct pointer to a @ref DrvSpiInitTypedef structure
 * @return SPI is initialized or not
 * @retval kSuccess SPI registers are initialized
 * @retval kError SPI registers are not initialized
 */
ErrorStatus DrvSpiInit(SpiTypedef* spi_instance, DrvSpiInitTypedef* spi_init_struct) {
  ErrorStatus status = kError;
  /* Check the SPI instance spi_instance*/
  assert_param(IS_SPI_ALL_INSTANCE(spi_instance));

  /* Check the SPI parameters from SPI_InitStruct*/
  assert_param(IS_DRV_SPI_TRANSFER_DIRECTION(spi_init_struct->direction));
  assert_param(IS_DRV_SPI_MODE(spi_init_struct->mode));
  assert_param(IS_DRV_SPI_DATAWIDTH(spi_init_struct->data_width));
  assert_param(IS_DRV_SPI_POLARITY(spi_init_struct->clk_polarity));
  assert_param(IS_DRV_SPI_CLOCKPHASE(spi_init_struct->clk_phase));
  assert_param(IS_DRV_SPI_BAUDRATEPRESCALER(spi_init_struct->baud_rate_prescaler));
  assert_param(IS_DRV_SPI_SIGNIFICANTBIT(spi_init_struct->first_bit));

  if (!DrvSpiIsEnabled(spi_instance)) {
    MODIFY_REG(spi_instance->GCTL,
               SPI_GCTL_MM | SPI_GCTL_3WIRE_BUS | SPI_GCTL_SIMPLEX_MODE | SPI_GCTL_TXEN | SPI_GCTL_RXEN,
               spi_init_struct->direction | spi_init_struct->mode);
    MODIFY_REG(spi_instance->CCTL,
               SPI_CCTL_CKPH |SPI_CCTL_CKPL | SPI_CCTL_LSBFE | SPI_CCTL_SPILEN,
               spi_init_struct->clk_polarity | spi_init_struct->clk_phase |
               spi_init_struct->first_bit | spi_init_struct->data_width);
    MODIFY_REG(spi_instance->SPBRG,
               SPI_SPBRG_BAUDRATE,
               spi_init_struct->baud_rate_prescaler);
    status = kSuccess;
  }

  return status;
}

/**
 * @fn void DrvSpiStructInit(DrvSpiInitTypedef* spi_init_struct)
 * @brief Set each @ref DrvSpiInitTypedef field to default value
 * 
 * @param[out] spi_init_struct pointer to a @ref DrvSpiInitTypedef structure
 *             whose fields will be set to default values
 * @return None
 */
void DrvSpiStructInit(DrvSpiInitTypedef* spi_init_struct) {
  /* Set spi_init_struct fields to default values */
  spi_init_struct->direction           = DRV_SPI_FULL_DUPLEX;
  spi_init_struct->mode                = DRV_SPI_MODE_MASTER;
  spi_init_struct->data_width          = DRV_SPI_DATAWIDTH_8BIT;
  spi_init_struct->clk_polarity        = DRV_SPI_POLARITY_LOW;
  spi_init_struct->clk_phase           = DRV_SPI_PHASE_1EDGE;
  spi_init_struct->baud_rate_prescaler = DRV_SPI_BAUDRATEPRESCALER_DIV2;
  spi_init_struct->first_bit           = DRV_SPI_MSB;
}

/** @} SPI_DRV_EF_Init */
/** @} SPI_DRV_Exported_Functions */
/** @} SPI_DRV */
/** @} GT98xx_DRV */
